﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Security.Permissions;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace AutoServey
{
    [PermissionSet(SecurityAction.Demand, Name = "FullTrust")]
    [System.Runtime.InteropServices.ComVisibleAttribute(true)]
    public partial class GooglePanoSearch : Form
    {
        private StreetViewManager streetViewManager = new StreetViewManager();
        private const double EARTH_RADIUS = 6378.137;
        private const int distance = 10;
        public static string geometry;

        public static GooglePanoSearch Instance;
        public static GooglePanoSearch GetInstance()
        {
            if (Instance == null || Instance.IsDisposed)
            {
                Instance = new GooglePanoSearch();
            }
            return Instance;
        }
        public GooglePanoSearch()
        {
            InitializeComponent();
            Instance = this;
        }

      
        public bool isInRegion(double lat, double lng)
        {
            if (getMinPointLineDis(geometry, lat, lng) <= distance)
            {
                return true;
            }
            return false;
        }

        public double getMinPointLineDis(string geometry, double lat, double lng)
        {
            double minDis = 20.0;
            string geo = geometry.Split('(')[1].Split(')')[0];
            string[] latlngs = geo.Split(',');
            for (int i = 0; i < latlngs.Length - 1; i++)
            {
                double dis = getPointLineDis(latlngs[i], latlngs[i + 1], lat, lng);
                if (minDis > dis)
                {
                    minDis = dis;
                }
            }
            return minDis;
        }

        public double getPointLineDis(string line1, string line2, double lat, double lng)
        {
            double minDis = 0.0;
            double lat1 = Convert.ToDouble(line1.Trim().Split(' ')[1]);
            double lng1 = Convert.ToDouble(line1.Trim().Split(' ')[0]);
            double lat2 = Convert.ToDouble(line2.Trim().Split(' ')[1]);
            double lng2 = Convert.ToDouble(line2.Trim().Split(' ')[0]);

            //向量点乘
            double cross = (lat - lat1) * (lat2 - lat1) + (lng - lng1) * (lng2 - lng1);
            double d2 = (lat2 - lat1) * (lat2 - lat1) + (lng2 - lng1) * (lng2 - lng1);
            //距离点x1更近
            if (cross <= 0)
            {
                minDis = getPointsDis(lat, lng, lat1, lng1);
            }
            //距离点x2更近
            else if (cross >= d2)
            {
                minDis = getPointsDis(lat, lng, lat2, lng2);
            }
            else
            {
                double latP = lat1 + (lat2 - lat1) * cross / d2;
                double lngP = lng1 + (lng2 - lng1) * cross / d2;
                minDis = getPointsDis(lat, lng, latP, lngP);
            }
            return minDis;
        }

        public double getPointsDis(double lat1, double lng1, double lat2, double lng2)
        {
            double radLat1 = rad(lat1);
            double radLat2 = rad(lat2);
            double a = radLat1 - radLat2;
            double b = rad(lng1) - rad(lng2);
            double s = 2 * Math.Asin(Math.Sqrt(Math.Pow(Math.Sin(a / 2), 2) +
             Math.Cos(radLat1) * Math.Cos(radLat2) * Math.Pow(Math.Sin(b / 2), 2)));
            s = s * EARTH_RADIUS;
            s = Math.Round(s * 10000) / 10000;
            return s * 1000;
        }

        public double rad(double angle)
        {
            return angle / 180 * Math.PI;
        }


        public void setPanoByLocation(double lat, double lng)
        {
            wbGM.Document.InvokeScript("setPanoByLocation", new object[] { lat, lng });
        }

        public void setPanoByID(string panoId)
        {
            wbGM.Document.InvokeScript("setPanoByID", new object[] { panoId });
        }

        public void receivePanoInfo(string infoType, string infoString)
        {
            MessageBox.Show(infoString, infoType);
        }

        public void receivePanoParams(string idString, string linksString, string positionString)
        {
            streetViewPoint newPoint = new streetViewPoint();
            newPoint.streetViewID = idString;
            positionString = positionString.Substring(1, positionString.Length - 2);
            string[] posArray = positionString.Split(',');
            posArray[1] = posArray[1].Substring(1, posArray[1].Length - 1);

            newPoint.la = Convert.ToDouble(posArray[0]);
            newPoint.lo = Convert.ToDouble(posArray[1]);
            newPoint.links = linksString.Split(',');

            if (isInRegion(newPoint.la, newPoint.lo) == true)
            {
                if (streetViewManager.addStreetViewPoint(newPoint))
                {
                    foreach (string newID in newPoint.links)
                    {
                        streetViewManager.insertPointID(newID);
                    }
                }
            }

            //调度下一个点
            string nextPointID = streetViewManager.getNextPointID();
            if (nextPointID != string.Empty)
            {
                setPanoByID(nextPointID);
            }
            else
            {
                exportStreetViewPoints();
                this.Close();
                return;
            }
        }

        private void exportStreetViewPoints()
        {
            string pano = "";
            foreach (streetViewPoint svPoint in streetViewManager.pointHashTable.Values)
            {
                string line = "(" + svPoint.la.ToString() + ", " + svPoint.lo + "),";
                pano += line;
            }
            XmlExport xmlExport = new XmlExport();
            XmlInput xmlInput = new XmlInput();

            string xmlPath = FrmMain.GetInstance().xmlPath;
            if (pano.Length > 0)
            {
                xmlExport.writePanoLocation(xmlPath, pano.Substring(0, pano.Length - 1));
                xmlInput.readXml(xmlPath);
            }
        }


        public void start()
        {
            string geo = geometry.Split('(')[1].Split(')')[0];
            string[] latlngs = geo.Split(',');
            double lat = Convert.ToDouble(latlngs[0].Trim().Split(' ')[1]);
            double lng = Convert.ToDouble(latlngs[0].Trim().Split(' ')[0]);
            setPanoByLocation(lat, lng);
        }

        private void GooglePanoSearch_Load(object sender, EventArgs e)
        {
            string url = FrmMain.GetInstance().AppPath + @"/GoogleStreetView.html";
            this.wbGM.Navigate(url);
            this.wbGM.ObjectForScripting = this;
            this.wbGM.ScriptErrorsSuppressed = true;
        }
    }
}
